home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d2 / sda13.arc / SDA13.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-24  |  26.7 KB  |  550 lines

  1.                                                                                 /*
  2.   sda13.c  06-17-90  (S)uper (D)irectory showing (A)ttributes: Ver. 1.3.
  3.   Slight modification of original program in NSD10A.ZIP by Bob Montgomery.
  4.   *  Ver. 1.1 fixed exit foreground color to white from red!
  5.   *  Ver. 1.2 expanded the max filenames handled from 500 to 718.
  6.   *  Ver. 1.3 06-17-90 warned of too many filenames selected (>718),
  7.           and showed pgm name and version in final line (in place of
  8.           arrows help text) if screen not filled by selected files.
  9.  
  10.   SDA displays a four-up directory listing. With a color CRT, the display
  11.   will present a different color for each file attribute such as ARCHIVE,
  12.   READ-ONLY, READ-WRITE, DIRECTORY, and SYSTEM/HIDDEN.
  13.  
  14.   SDA has been tested under PC DOS 3.3, and 4.0 on a 320 MB hard drive:
  15.   the file count and free space amounts seem to be correct.
  16.  
  17.   If a file size is one meg or larger, SDA shows 999,999 to be able to fit
  18.   four up.  If the selected files in a directory total more than 718, SDA
  19.   returns a message rather than an incomplete display as SDA ver. 1.2 did.
  20.  
  21.   If the directory fits on one screen, the last line is the TOTALS line,
  22.   and the SDA version and date appear in the last line in place of text
  23.   concerning use of keypad keys for scrolling.
  24.  
  25.   If the directory overflows one screen, the bottom non-scrollabel line
  26.   is the TOTALS line.  The TOTALS line also contains a reminder to use the
  27.   arrow keys (when display overflows one screen), and has the color sceme
  28.   for the file attributes so that you do now have to memorize this screen!
  29.   The TOTALS line also shows a file count and space free.
  30.  
  31.   The main purpose of SDA is to spot files which need backup, are read-only,
  32.   or are system or hidden files.
  33.  
  34.   Colors used in the 4-up DIR display are:
  35.      Directories    12  Lt Red
  36.      Hidden          8  Gray
  37.      System          8  Gray
  38.      Read-only      15  Hi White
  39.      Read-write     10  Hi Green: majority of files
  40.      Archive ON     14  Yellow (for caution, not backed up.)
  41.             This was added to NSD10A original.
  42.      -----------------
  43.      Totals line    11  Hi Cyan    9 Hi Blue    etc.
  44.  
  45.  
  46.   =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  47.  
  48.   Microsoft `C`, Ver. 5.1 or QuickC 2.0 compile and link batch file:
  49.  
  50.   @ECHO OFF
  51.   Rem CLSDA.BAT 06-17-90 tem
  52.  
  53.   cl SDA13.c  /Zp /c 
  54.      If errorlevel 1 Echo Error in %0.  Link step NOT DONE.
  55.      If errorlevel 1 GOTO @FINIS
  56.  
  57.   Rem DO NOT pack if using stack option...
  58.       Link /STACK:8192  sda13+putstr.obj;
  59.  
  60. :@FINIS
  61.  
  62.   =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  63.  
  64.  
  65.   08-06-89 Version 1.0 TEM
  66.   SDA fixed an apparant bug: when file count was within a few of a full
  67.   screen, the original program ended scrolling the disply up a line.
  68.   This caused the top line of files to "disappear" from the display.
  69.   Now the escape key must be pressed in such situations before the
  70.   program will end, and the scrolling occurs. This requires a positive
  71.   action by the user.
  72.  
  73.  
  74.   -----------------------------------------------------------------------
  75.  
  76.   Original program intro etc follows:
  77.  
  78.   By Bob Montgomery, Orlando, Fla. CIS [73357,3140]                7-10-88
  79.   SORT.C is a program which reads a directory and prints the files in alph-
  80.   betical order to the screen. It is about as fast as SD, and illustates the
  81.   use of a binary tree to do sorting. It also illustrate other concepts
  82.   useful in writing applications, such as:
  83.      1. Interfaceing with assy language (putstr.8).
  84.      2. Accessing C's global varaiables in assy language.
  85.      3. Using far pointers in a small model program.
  86.      4. Getting drive parameters.
  87.      5. Screen management.
  88.      6. Very fast clear screen.
  89.      7. Displaying large numbers with commas.
  90.  
  91.   Compile with Microsoft C using the /Zp option to pack structures, and
  92.   then link sort.obj and putstr.obj. If you modify putstr.8 and don't have
  93.   A86, you can add all the 'red tape' required by MASM and assemble
  94.   putstr.8, or better yet, get A86 and assemble with the +cs options to
  95.   make case sensitive. Print at 132 chars/line and 88 lines/page for most
  96.   readable results.
  97.  
  98.   The binary tree has nodes, where each node consists of a string, and a
  99.   left and right pointer to the next node.
  100.  
  101.   The rules for building the tree are:
  102.      1. Make all left and right pointers null.
  103.      2. Always start at the root node.
  104.      3. If the new string is lower (alphabetically) than the string at a node,
  105.         look at the left node; if higher look at the right node.
  106.      4. If the next node is null, set the pointer (right or left) to the next
  107.         node, and then copy the string to the next node. Otherwise, continue
  108.         the search branching left or right as required.
  109.   The rule for outputing the data alphabetically are:
  110.      1. Start at the root node.
  111.      2. Check to the left node. if it is not null, go to it, otherwise output
  112.         the string at this node, and then check the right node. If it is not
  113.         null, go to it, otherwise go to the previous node.
  114.   The output routine is best accomplished using a recursive function (one
  115.   which calls itself). This automatically takes care of the movement up and
  116.   down the tree.  Here, that function is untree().
  117.  
  118. */
  119.  
  120. #include "stdio.h"                 /* For printing to screen */
  121. #include "dos.h"                   /* For _dos_findfirst and _dos_findnext */
  122. #include "string.h"                /* For string functions */
  123. #include "process.h"               /* For exit function */
  124. #include "malloc.h"                /* For memory allocation */
  125.  
  126. #define   PAGE_UP        73        /* Define command keys */
  127. #define   PAGE_DOWN      81
  128. #define   LEFT_ARROW     75
  129. #define   RIGHT_ARROW    77
  130. #define   UP_ARROW       72
  131. #define   DOWN_ARROW     80
  132. #define   ESC            27
  133. #define   FILEATTR       0x37      /* File attributes; select all but volume labels */
  134. #define   READONLY       1
  135. #define   HIDDEN         2
  136. #define   SYSTEM         4
  137. #define   ARCHIVE        32
  138. #define   SUBDIR         16
  139.  
  140. struct node                        /* Define tree node structure */
  141. {    char name[20];                     /* Filename and size string */
  142.      int  attr;                         /* File attribute */
  143.      struct node *left, *right;         /* Left and right branch pointers */
  144. } ;
  145.  
  146. struct fname                       /* Define filename array */
  147. {    char name[20];                     /* Filename and size string */
  148.      int  attr;                         /* File attribute */
  149. } ;  
  150. struct                             /* Allocate DTA and define structure */
  151. {    char path[21];                     /* DOS path and filespec */
  152.      char attribute;                    /* File attributes wanted */
  153.      int  ftime;                        /* File creation time */
  154.      int  fdate;                        /* File creation date */
  155.      long size;                         /* File size in bytes */
  156.      char filename[13];                 /* Filename and extension */
  157. } DTA;                                  /* Disk Transfer Area */
  158.  
  159. char Nomemmsg[] = "SDA limit of 718 filenames exceeded."; /* Define messages */
  160. char dir1[] = "*.*";
  161. char dir2[] = "\\*.*";
  162. /*   */
  163.  
  164. /**************************  Global variables  ************************/
  165.  
  166. /*  1 Blue      2 Green       3 Cyan         4 Red        5 Magenta
  167.     6 Brown     7 White       8 Gray         9 Lt Blue   10 Lt Green
  168.    11 Lt Cyan  12 Lt Red     13 Lt Magenta  14 Yellow    15 Lt White
  169. */
  170.  
  171. int  dirattr  = 12;        /* Directory entries */
  172. int  hidattr  = 8;         /* Hidden files */
  173. int  r_oattr  = 15;        /* Read-only    */
  174. int  sysattr  = 8;         /* System files */
  175. int  arcattr  = 14;        /* Archive attribute is ON */
  176. int  normattr = 10;        /* Normal: files with archive bit OFF */
  177. int  msgattr  = 11;        /* Totals line  */
  178. int  lt_blue  = 9;         /* Light Blue for program ID  */
  179.  
  180. union REGS regs;                     /* For DOS and BIOS calls */
  181. long disksize, dirsize, free_bytes;  /* Disk sizes */
  182. unsigned video_seg;                  /* Current video display segment */
  183. int crtrows, crtcols, drive;         /* Lines/page, columns/row, and drive */
  184. int  dircount;                       /* Number of subdirectories found */
  185.  
  186. char *tempstr;                       /* Temporary string workfield */
  187.  
  188. /* Define functions */
  189. struct fname *untree(struct node *, struct fname *);
  190. int  getfiles(char *, struct fname *);
  191. void cls();
  192. void setcursor(int, int);
  193. void get_drive_data();
  194. void getdrive();
  195. void format(char *, long);
  196. int  findfirst(char *);
  197. int  findnext();
  198.  
  199. /* ======================================================= */
  200.  
  201.  
  202. main(argc, argv)
  203. int  argc;                         /* Number of arguments */
  204. char *argv[];                      /* Pointers to arguments */
  205. {    struct fname *dptr;           /* Pointer to filename/size structure */
  206.      int  count, video_mode;       /* Number of files found, current video mode */
  207.      char *dir, *end, *ptr, ch;    /* Command line pointers */
  208.      unsigned char far *lowptr;    /* Low memory pointer */
  209.  
  210.      if ((dptr = (struct fname *)malloc(32768)) == NULL)  /* Allocate memory for array of filenames */
  211.      {    puts(Nomemmsg); goto A2; }
  212.  
  213. /* Parse command line for path:filespec */
  214.      if (argc > 1)                           /* If a filespec was passed */
  215.      {    end = dir = argv[1];                    /* Point to it */
  216.           while (*end) end++;                     /* Find the end of the string */
  217.           end--;
  218.           if ((ch = *end) == ':' || ch == '\\') strcat(dir, dir1); /* If it ends in \ or : add *.* */
  219.           else if ((ptr = strchr(dir, '.')) != NULL)   /* else if there is a period */
  220.           {    if (ptr == dir)                              /* If 1st char is a . */
  221.                {    if (*(end-1) == '*' && ch == '.') ;          /* If last 2 chars are *. do nothing */
  222.                     if (ch == '*') ;                             /* If last char is * do nothing */
  223.                     else if (*end == '\\') strcat(dir,dir1);     /* If last char is \, add *.* */
  224.                     else strcat(dir,dir2);                       /* else add \*.* */
  225.                }                                            /* Do nothing if filespec */
  226.           }
  227.           else strcat(dir, dir2);                 /* Otherwise, all files in directory specified */
  228.      }
  229.      else dir = dir1;                        /* Otherwise, all files in default directory */
  230.      count = getfiles(dir, dptr);            /* Get the sorted files to the structure dptr */
  231.      drive = 0;                              /* Assume default drive */
  232.      if ((ptr = strchr(dir, ':')) != NULL) drive = toupper(*(ptr-1)) - 'A' + 1; /* If drive spec'd */
  233.      FP_SEG(lowptr) = 0;                     /* Set for low memory */
  234.      FP_OFF(lowptr) = 0x449;                 /* Get video mode */
  235.      if ((video_mode = *lowptr) >= 0 && video_mode < 4) video_seg = 0xB800; /* Define video segment */
  236.      else if (video_mode == 7)               /* If monochrome */
  237.      {    video_seg = 0xB000;
  238.           normattr = 7; dirattr = 15; hidattr = msgattr = 0x70; sysattr = 0x88;
  239.      }
  240.      else { printf("%d is a bad Video mode", video_mode); goto A1; }
  241.      FP_OFF(lowptr) = 0x484;                 /* Get screen rows -1 */
  242.      crtrows = (int)(*lowptr);
  243.      FP_OFF(lowptr) = 0x44A;                 /* Get columns/row */
  244.      crtcols = (int)(*lowptr);
  245.      if (video_mode == 7) { crtrows = 24; crtcols = 80; } /* Since some mono adapters don't update lower RAM */
  246.      if (count <= 0) puts("No files found"); /* Tell if no files meeting filespec */
  247.      else display(dptr, count);              /* else display the files */
  248.  
  249. A1:  free(dptr);                             /* Free the array buffer */
  250.  
  251. A2:  ;                                       /* Quit to DOS */
  252.  
  253. }
  254.  
  255. /*            ================================================ */
  256.  
  257. int getfiles(srchspec, buffer)     /* Get and sort all files in path/filespec */
  258. char *srchspec;                    /* Path/filespec */
  259. struct fname *buffer;              /* Filename structure to put them in */
  260. {    struct node *entry, *ptr;     /* Node structure pointers */
  261.      struct fname *fptr;           /* Filename structure pointer */
  262.      int count, errno, i;          /* # files and dirs */
  263.      char string[20];              /* Temporary string to hold file data */
  264.  
  265.      if ((entry = (struct node *)malloc(13000)) == NULL)  /* Allocate memory for the tree */
  266.      {    puts(Nomemmsg);
  267.           return (0);
  268.      }
  269.      for (i=0; i < 720; i++) entry[i].right = entry[i].left = NULL; /* Make all left & right pointers null */
  270.      count = dircount = 0;                         /* Reset file counters */
  271.      dirsize = 0;                                  /* Reset byte counter */
  272.  
  273.      if (errno = findfirst(srchspec)) goto B;      /* If no files found */
  274.  
  275.      ptr = &entry[0];                              /* Start at root */
  276.      while (errno == 0)  /* While there are files meeting filespec, build the tree */
  277.      {    if (DTA.attribute == 16) sprintf(string, "%-12s  <DIR>", DTA.filename);    /* Was a subdir */
  278.           else                               /* else was a file */
  279.           {    dirsize += DTA.size;          /* Add file size to byte counter */
  280.                if (DTA.size > 999999L) DTA.size = 999999L;  /* So won't overrun size space */
  281.                sprintf(string, "%-12s %6ld", DTA.filename, DTA.size); /* Copy file data to string */
  282.           }
  283.           if (!count)                        /* Fill in root entry if count = 0 */
  284.           {    strcpy(entry[0].name, string);
  285.                entry[0].attr = DTA.attribute;
  286.           }
  287.           else                               /* If root filled in */
  288.           {    ptr = &entry[0];              /* Start at root */
  289.                while (1)                     /* Keep going till null pointer found */
  290.                {    if ((i = strcmp(string, ptr->name)) < 0)     /* If string < name */
  291.                     {    if (ptr->left == NULL)                  /* If no pointer yet */
  292.                          {    ptr = ptr->left = &entry[count];   /* Set pointer to left side & go left */
  293.                               break;                             /* and quit loop */
  294.                          }
  295.                          else ptr = ptr->left;                   /* Else go to left */
  296.                     }
  297.                     else                                         /* If string > name */
  298.                     {    if (ptr->right == NULL)                 /* If no pointer to right */
  299.                          {    ptr = ptr->right = &entry[count];  /* Set pointer to right side & go right */
  300.                               break;                             /* and quit loop */
  301.                          }
  302.                          else ptr = ptr->right;                  /* Else go right */
  303.                     }
  304.                }                             /* Try next node till null found */
  305.                strcpy(ptr->name, string);    /* Copy name to this node */
  306.                ptr->attr = DTA.attribute;
  307.           }
  308.           if (DTA.attribute == 16) dircount++; /* Inc dir counter if a subdir found */
  309.           count++;                      /* Inc count */
  310.       if (count == 720) break;      /* Limit is 718 files */
  311.           errno = findnext();           /* Find next file */
  312.      }                                  /* Do it again */
  313. /* Now place the filenames in ascending order in the buffer */
  314.      ptr = &entry[0];                   /* Start at root */
  315.      fptr = buffer;                     /* Point to file buffer */
  316.      untree(ptr, fptr);                 /* Traverse tree, output to buf */
  317.  
  318. B:   free(entry);                       /* Free tree memory */
  319.      return (count);                    /* Return number of files found */
  320. }
  321. /* ================================================ */
  322. struct fname *untree(ptr, fptr)    /* Alphabetizes data to fptr */
  323. struct node *ptr;                  /* Node structure pointer */
  324. struct fname *fptr;                /* Filename buffer pointer */
  325. {    if (ptr != NULL)              /* If not pointing to null */
  326.      {    fptr = untree(ptr->left, fptr);    /* Go left */
  327.           strcpy(fptr->name, ptr->name);     /* Copy name to buffer */
  328.           fptr->attr = ptr->attr;            /* and file attribute */
  329.           fptr++;                            /* Next buffer position */
  330.           fptr = untree(ptr->right, fptr);   /* Go right */
  331.      }
  332.      return (fptr);                /* Return current buffer pointer */
  333. }
  334. /*            ============================================ */
  335. display(dptr, count)               /* Display the files */
  336. struct fname *dptr;                     /* Data to display */
  337. int  count;                             /* Number of entries */
  338. {    int start, flag, end, row, col, n, k, nextcol, nextscreen, driveflag;
  339.      int color, columns;
  340.      char line[80], dir[14], disk[14], free[14], ch, *ptr;
  341.  
  342.      start = driveflag = 0;                  /* Start at 1st file */
  343.      columns = crtcols / 20;                 /* Get # columns */
  344.      nextscreen = columns * crtrows;         /* Get # files for whole screen */
  345.      if (count <= nextscreen)                /* If all will go on 1 page */
  346.      {    nextcol = count / columns;         /* Get number to print/column */
  347.       if (count % columns) nextcol++;    /* Inc if not evenly divisible */
  348.      }
  349.      else nextcol = crtrows;                 /* else use all rows except last */
  350.      flag = ch = 1;                          /* Fool while statement */
  351.      while (flag || (ch = getch()) != ESC)   /* Do until escape pressed */
  352.      {    if (ch == 0) ch = getch();         /* Get command */
  353.           switch (ch)                             /* Adjust start index accordingly */
  354.           {    case RIGHT_ARROW:
  355.                     if (end < count) start += nextcol; /* If last not shown right 1 column */
  356.                     else break;
  357.                     flag++;
  358.                     break;
  359.                case LEFT_ARROW:
  360.                     if (start > 0)                     /* If not at first */
  361.                     {    start -= nextcol;                  /* Left one column */
  362.                          if (start < 0) start = 0;          /* Adjust */
  363.                     }
  364.                     else break;
  365.                     flag++;
  366.                     break;
  367.                case PAGE_UP:
  368.                     if (start)                         /* If start not at first file */
  369.                     {    if (start >= nextscreen) start -= nextscreen; /* Page back */
  370.                          else start = 0;                               /* or set start = first */
  371.                     }
  372.                     else break;
  373.                     flag++;
  374.                     break;
  375.                case PAGE_DOWN:
  376.                     if (end != count)             /* If not last page */
  377.                     {    if (end < (count - (columns - 1) * nextcol)) start += nextscreen; /* Page forward */
  378.                          else
  379.                          {    k = count - end;         /* Get # files not yet shown */
  380.                               n = k / nextcol;         /* Get full columns */
  381.                               if (k % nextcol) n++;    /* Adjust for partial columns */
  382.                               start += n * nextcol;    /* Set new start index */
  383.                          }
  384.                     }
  385.                     else break;
  386.                     flag++;
  387.                     break;
  388.                case UP_ARROW:
  389.                     if (start > 0)                /* If not at start */
  390.                     {    start--;                      /* Previous file */
  391.                          flag++;
  392.                     }
  393.                     break;
  394.                case DOWN_ARROW:
  395.                     if (end < count)              /* If not at end */
  396.                     {    start++;                      /* Next file */
  397.                          flag++;
  398.                     }
  399.           }
  400.           if (flag)                               /* If start index changed */
  401.           {    end = start + nextscreen;               /* Compute end index */
  402.                if (end > count) end = count;
  403.                cls();                                  /* Clear the screen */
  404.                for (row=0; row < nextcol; row++)       /* Do all rows */
  405.                {    for (col=0; col < columns; col++)       /* Do all columns */
  406.                     {    n = start + nextcol * col + row;                  /* Get index */
  407.                          if (n >= count) break;                            /* Stop if last one */
  408.                          if (col < (columns - 1)) k = 1; else k = 0;       /* File divider logic */
  409.                          if (dptr[n].attr & HIDDEN) color = hidattr;       /* Set attributes */
  410.                          else if (dptr[n].attr & SYSTEM) color = sysattr;
  411.                          else if (dptr[n].attr & READONLY) color = r_oattr;
  412.                          else if (dptr[n].attr & ARCHIVE) color = arcattr;
  413.                          else if (dptr[n].attr & SUBDIR) color = dirattr;
  414.                          else color = normattr;
  415.              putstring(row, 20 * col, color, dptr[n].name, 0); /* Print to display */
  416.                     }
  417.                }
  418. /*   */
  419.                if (!driveflag)               /* If we haven't got drive data yet */
  420.                {    get_drive_data();             /* Get the drive data */
  421.                     format(dir, dirsize);         /* Format sizes with commas */
  422.                     format(disk, disksize);
  423.                     format(free, free_bytes);
  424.                     driveflag++;                  /* Don't do again */
  425.                }
  426.  
  427.                sprintf(line, "%d files  %s free                             ",
  428.                         (count - dircount), free);
  429.                putstring(nextcol, 0, msgattr, line, 0);
  430.  
  431.      if ((count - dircount) - 718 == 0)
  432.      {  cls();
  433.     sprintf(line, "    Number of filenames selected was greater than 717 SDA maximum.           ");
  434.     putstring(nextcol, 3, dirattr, line, 0);
  435.     exit(1);
  436.      }
  437.  
  438.            sprintf(line, " SDA Ver 1.3 06/90  ");     /* If all fits on*/
  439.            putstring(nextcol, 29, lt_blue, line, 0);  /* just 1 screen */
  440.  
  441.      if ((count - dircount) - 94 > 0)
  442.      {
  443.            sprintf(line, "PgUp/Dn/Arrow/Esc.  ");     /* More than one */
  444.            putstring(nextcol, 30, lt_blue, line, 0);  /* screen worth..*/
  445.      }
  446.  
  447.                tempstr = "Attr: ";
  448.                putstring(nextcol, 50, msgattr, tempstr, 0);
  449.  
  450.            tempstr = "Dir ";
  451.            putstring(nextcol, 56, dirattr, tempstr, 0);
  452.  
  453.                tempstr = "Sys/Hid ";
  454.            putstring(nextcol, 60, sysattr, tempstr, 0);
  455.  
  456.            tempstr = "R-O ";
  457.            putstring(nextcol, 68, r_oattr, tempstr, 0);
  458.  
  459.            tempstr = "Arc ";
  460.            putstring(nextcol, 72, arcattr, tempstr, 0);
  461.  
  462.            tempstr = "R-W ";
  463.            putstring(nextcol, 76, normattr, tempstr, 0);
  464.  
  465.                flag = 0;                     /* Clear the command flag  */
  466.           }
  467.       if (count < (nextscreen - columns)) break;    /* Quit if screen not full */
  468.      }
  469.      setcursor(nextcol, 0);                  /* Set cursor for DOS exit */
  470.  
  471.   /* printf("count   = %d  nextscreen = %d", count, nextscreen); */ /* Debug */
  472.   /* printf("columns = %d  crtrows    = %d", columns, crtrows);  */ /* Debug */
  473.  
  474.  
  475. }
  476.  
  477. /* =========================================== */
  478. void cls()               /* Clears the screen on the spec'd page */
  479. {    setcursor(0, 0);
  480.      regs.x.ax = 0x920;            /* Write char & attr-char = space */
  481.      regs.x.bx = 6;                /* Page 0, color 6 */
  482.      regs.x.cx = crtrows * crtcols; /* Whole screen to write */
  483.      int86(0x10, ®s, ®s);
  484. }
  485.  
  486. /*  ========================================== */
  487. void setcursor(row, col) /* Set cursor to row, col thru BIOS */
  488. int row, col;
  489. {    regs.h.ah = 2;           /* BIOS set cursor function */
  490.      regs.h.bh = 0;           /* Page 0 */
  491.      regs.h.dh = row;
  492.      regs.h.dl = col;
  493.      int86(0x10,®s,®s);
  494. }
  495. /* ========================================== */
  496. void get_drive_data()    /* Gets data for drive */
  497. {    int  sectors_per_cluster, bytes_per_sector;
  498.      unsigned total_clusters, free_clusters;
  499.      int  bytes_per_cluster, dir_clusters;
  500.      
  501.      regs.h.ah = 0x36;                            /* Get disk parameters */
  502.      regs.h.dl = drive;                           /* 0=default, 1=A, etc */
  503.      intdos(®s, ®s);
  504.      total_clusters = regs.x.dx;                  /* Get data */
  505.      free_clusters = regs.x.bx;
  506.      sectors_per_cluster = regs.x.ax;
  507.      bytes_per_sector = regs.x.cx;
  508.      bytes_per_cluster = sectors_per_cluster * bytes_per_sector; /* Compute some more data */
  509.      disksize = (long)bytes_per_cluster * (long)total_clusters;
  510.      free_bytes = (long)bytes_per_cluster * (long)free_clusters;
  511. }
  512. /* ================================================ */
  513. void format(ptr, size)   /* Format the long number size to string ptr using commas */
  514. char *ptr;
  515. long  size;
  516. {    int  mil, tho, ones;
  517.      char *tmp, fmt[6];
  518.  
  519.      mil = (int)(size / 1000000L);                  /* Get millions */
  520.      tho = (int)((size - 1000000L * (long)mil) / 1000);  /* Get thousands */
  521.      ones = size % 1000;                          /* Get ones */
  522.      *(tmp = ptr) = 0;                            /* Point to output string */
  523.      if (mil) sprintf(tmp, "%d,", mil);           /* If millions, print them and comma */
  524.      while (*tmp) tmp++;                          /* Find end of millions */
  525.      if (mil) sprintf(tmp, "%03d,", tho);         /* If millions, print 3 digits for thousands & comma */
  526.      else if (tho) sprintf(tmp, "%3d,", tho);     /* else if tousands, print them and comma */
  527.      while (*tmp) tmp++;                          /* Find end of thousands */
  528.      if (mil || tho) sprintf(tmp, "%03d", ones);  /* If millions or thousands, print ones */
  529.      else sprintf(tmp, "%3d", ones);              /* else print ones */
  530. }
  531. /* ===================================================== */
  532. int  findfirst(path)     /* Find 1st file (or subdir) meeting path/filespec */
  533. char *path;                   /* DOS path/filespec */
  534. {    regs.h.ah = 0x1A;             /* Set DTA to filedata */
  535.      regs.x.dx = (unsigned)&DTA;
  536.      intdos(®s, ®s);
  537.      regs.h.ah = 0x4E;             /* Find 1st file meeting path */
  538.      regs.x.dx = (unsigned)path;
  539.      regs.x.cx = FILEATTR;
  540.      intdos(®s, ®s);
  541.      return(regs.x.ax);            /* Return error code */
  542. }
  543. /*  ===================================================== */
  544. int  findnext()          /* Find next file (or subdir) meeting above path/filespec */
  545. {    regs.h.ah = 0x4F;             /* Find next file meeting path */
  546.      regs.x.dx = (unsigned)&DTA;
  547.      intdos(®s, ®s);
  548.      return(regs.x.ax);
  549. }
  550.